﻿<!DOCTYPE html>
<!--[if IE]><![endif]-->
<html>
  
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <title>Localization </title>
    <meta name="viewport" content="width=device-width">
    <meta name="title" content="Localization ">
    <meta name="generator" content="docfx 2.59.2.0">
    
    <link rel="shortcut icon" href="../../../favicon.ico">
    <link rel="stylesheet" href="../../../styles/docfx.vendor.css">
    <link rel="stylesheet" href="../../../styles/docfx.css">
    <link rel="stylesheet" href="../../../styles/main.css">
    <link rel="stylesheet" href="../../../styles/socialbar.css">
    <link rel="stylesheet" href="../../../styles/header.css">
    <link rel="stylesheet" href="../../../styles/version.css">
    <link href="https://fonts.googleapis.com/css?family=Roboto:400,100,300,500,700,100italic,300italic,400italic" rel="stylesheet" type="text/css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
    <meta property="docfx:navrel" content="../../../toc.html">
    <meta property="docfx:tocrel" content="../../toc.html">
    <meta property="docfx:uid" content="doc-plugins-ui-localization">
    
    <meta property="docfx:rel" content="../../../">
    
    <script type="text/javascript" src="../../../nav.js"></script>
    <script type="text/javascript" src="../../toc.js"></script>
  
  </head>  <body data-spy="scroll" data-target="#affix" data-offset="120">
    <div id="wrapper">
      <header>
        
        <div class="mb-socials-heading" style="height: 40px;">
        	<div class="mb-socials-heading-inner container">
        		<div class="mb-socials-heading-right">
        			<div class="mb-socials-list">
                          
        				<div class="mb-socials-item facebook">
        					<a class="mb-socials-item-link" target="_blank" href="https://facebook.com/embyapp"></a>
        					<div class="mb-socials-item-popup">
        						<span>Facebook</span>
        					</div>
        				</div><div class="mb-socials-item twitter">
        					<a class="mb-socials-item-link" target="_blank" href="https://twitter.com/embyapp"></a>
        					<div class="mb-socials-item-popup">
        						<span>Twitter</span>
        					</div>
        				</div>
        				<div class="mb-socials-item pinterest">
        					<a class="mb-socials-item-link" target="_blank" href="https://www.pinterest.com/emby0240/emby-news/"></a>
        					<div class="mb-socials-item-popup">
        						<span>Pinterest</span>
        					</div>
        				</div>
        				<div class="mb-socials-item tumblr">
        					<a class="mb-socials-item-link" target="_blank" href="https://embyapp.tumblr.com/"></a>
        					<div class="mb-socials-item-popup">
        						<span>Tumblr</span>
        					</div>
        				</div>
        				<div class="mb-socials-item github">
        					<a class="mb-socials-item-link" target="_blank" href="https://github.com/MediaBrowser"></a>
        					<div class="mb-socials-item-popup">
        						<span>GitHub</span>
        					</div>
        				</div><div class="mb-socials-item rss">
        					<a class="mb-socials-item-link" target="_blank" href="https://emby.media/blog.xml"></a>
        					<div class="mb-socials-item-popup">
        						<span>RSS</span>
        					</div>
        				</div>
                          
        			</div>
        		</div>
        	</div>
        </div>
        <div class="container">
        	<nav id="autocollapse" class="navbar navbar-inverse ng-scope" role="navigation">
        		  
        		  <a class="navbar-brand" href="../../../index.html">
        		    <img id="logo" class="svg" src="../../../images/emby_dev_logo.png" alt="">
        		  </a>
        		  <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navbar">
        			<span class="sr-only">Toggle navigation</span>
        			<span class="icon-bar"></span>
        			<span class="icon-bar"></span>
        			<span class="icon-bar"></span>
        		  </button>
        		<div class="collapse navbar-collapse" id="navbar">
        			
        			<ul class="nav level1 navbar-nav">
        			      <li class="nav-item">
        			          <a class="nav-link" href="../../../index.html" title="DEV Home">DEV Home</a>
        			      </li>
        			      <li class="nav-item">
        			          <a class="nav-link" href="../../../doc/index.html" title="Documentation">Documentation</a>
        			      </li>
        			      <li class="nav-item">
        			          <a class="nav-link" href="../../../reference/index.html" title="Reference">Reference</a>
        			      </li>
        			      <li class="nav-item">
        			          <a class="nav-link" href="../../../download/index.html" title="Download">Download</a>
        			      </li>
        			</ul>		</div>
        	</nav>
        </div>
        <div class="nav-overlay d-none"></div>        
        <div class="subnav navbar navbar-default">
          <div class="container">
            <div class="hide-when-search" id="breadcrumb">
        	  <ul class="breadcrumb">
        		<li></li>
        	  </ul>
        	</div>
        
        	<div class="breadcrumpsearch">
        	  <form class="navbar-form navbar-right" role="search" id="search">
        		<div class="form-group">
        		  <input type="text" class="form-control" id="search-query" placeholder="Search" autocomplete="off">
        		</div>
        	  </form>
        	</div>
          </div>
        </div>
      </header>
      <div class="container body-content">
        
        <div id="search-results">
          <div class="search-list">Search Results for <span></span></div>
          <div class="sr-items">
            <p><i class="glyphicon glyphicon-refresh index-loading"></i></p>
          </div>
          <ul id="pagination" data-first="First" data-prev="Previous" data-next="Next" data-last="Last"></ul>
        </div>
      </div>
      <div role="main" class="container body-content hide-when-search">
        
        <div class="sidenav hide-when-search">
          <a class="btn toc-toggle collapse" data-toggle="collapse" href="#sidetoggle" aria-expanded="false" aria-controls="sidetoggle">Show / Hide Table of Contents</a>
          <div class="sidetoggle collapse" id="sidetoggle">
            <div id="sidetoc"></div>
          </div>
        </div>
        <div class="article row grid-right">
          <div class="col-md-10">
            <article class="content wrap" id="_content" data-uid="doc-plugins-ui-localization">
<h1 id="localization">Localization</h1>

<p>Localizing applications can be quite tedious, but there are lots of tools available which can help on this procedure.
These allow developers to easily localize an application as a secondary step, so that the primary development can be done without caring about localization requirements and tasks.</p>
<p>Using Emby GenericUI, you don't have to deal with HTML and Javascript code. You are developing your plugin as a .NET class library and as such, you are able to employ standard procedures for localizing .NET applications using Resource.resx files and Visual Studio tooling (optionally with the help of VS extensions).</p>
<h2 id="tools">Tools</h2>
<p>Many tools and extensions exist. The ones we are using internally are:</p>
<ul>
<li><a href="https://www.jetbrains.com/resharper/">ReSharper</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=TomEnglert.ResXManager">ResXManager</a></li>
</ul>
<h3 id="strings-in-attributes">Strings in Attributes</h3>
<p>Using the Emby Plugin UI framework, you will often end up with a lot of member atttributes in your code which are containing strings that need to be localized. Unfortunately there do not exist any tools to help with the localization of those strings and even <a href="https://www.jetbrains.com/resharper/">ReSharper</a> cannot do that out-of-the box.</p>
<p>This made us create a custom extension for ReSharper for our own needs, which we have published for free:</p>
<p><strong>LocalizationTools.ReSharper</strong></p>
<ul>
<li><a href="https://github.com/LocalizationTools/LocalizationTools.ReSharper">https://github.com/LocalizationTools/LocalizationTools.ReSharper</a></li>
<li><a href="https://plugins.jetbrains.com/plugin/19783-attribute-localization-for-resharper">https://plugins.jetbrains.com/plugin/19783-attribute-localization-for-resharper</a></li>
</ul>
<p>The following animation shows the way it works:</p>
<p><img src="../../../images/resh_attrib_localization.png" alt="Resharper Attrib Localization"></p>
<p>The only required preparaion is to change the attributes to localizable attributes. You can simply use the ones we ship with our Nuget libaries. Reference here: <a class="xref" href="../../../reference/pluginapi/MediaBrowser.Model.LocalizationAttributes.html">MediaBrowser.Model.LocalizationAttributes</a></p>
<p>Essentially, you only need to append the letter <code>L</code> to all atttributes, so</p>
<p><code>[Description(&quot;My description&quot;)]</code></p>
<p>becomes</p>
<p><code>[DescriptionL(&quot;My description&quot;)]</code></p>
<p>After that, R# will offer you to localize the attribute strings.</p>
<p>Caveat: First, you need to add a Resources.resx file to the project and add at least a single string resource.</p>
<h2 id="building-and-deployment">Building and Deployment</h2>
<p>There's one little problem, though: Localization with .NET works in a way that  satellite DLLs are created during compilation for each supported language that are located in subfolders of the compiled DLL.
This is incompatible with the way you are publishing plugins to the Emby catalog and again incompatible with the way how Emby is loading the plugins.</p>
<p>Gladly, there's an easy solution to this problem. All you need to do is to add the Nuget package <code>Resource.Embedder</code> to your plugin project. After doing so, all language resources will be embedded in the compiled plugin DLL.</p>
<p>See also:</p>
<ul>
<li><a href="https://www.nuget.org/packages/Resource.Embedder">https://www.nuget.org/packages/Resource.Embedder</a></li>
<li><a href="https://github.com/MarcStan/Resource.Embedder">https://github.com/MarcStan/Resource.Embedder</a></li>
</ul>
</article>
          </div>
          
          <div class="hidden-sm col-md-2" role="complementary">
            <div class="sideaffix">
              <div class="contribution">
                <ul class="nav">
                </ul>
              </div>
              <div class="sdkversion Release">
                  SDK <span class="sdkVersionSpan"></span>
              </div>
              <nav class="bs-docs-sidebar hidden-print hidden-xs hidden-sm affix" id="affix">
                <h5>On this Page</h5>
                <div></div>
              </nav>
            </div>
          </div>
        </div>
      </div>
      
      <footer>
        <div class="grad-bottom"></div>
        <div class="footer">
          <div class="container">
            <span class="pull-right">
              <a href="#top">Back to Top</a>
            </span>
            Copyright 2022 © EMBY LLC.  Please see our <a class="lnk" href="https://emby.media/terms.html">terms of use</a> and <a class="lnk" href="https://emby.media/privacy.html">privacy policy</a>.
            
          </div>
        </div>
      </footer>
    </div>
    
    <script type="text/javascript" src="../../../styles/docfx.vendor.js"></script>
    <script type="text/javascript" src="../../../searchIndex.js"></script>
    <script type="text/javascript" src="../../../styles/lunr.min.js"></script>
    <script type="text/javascript" src="../../../styles/docfx.js"></script>
    <script type="text/javascript" src="../../../styles/main.js"></script>
  </body>
</html>
